using System;
using System.Threading;
using Needle.Framework;

namespace Needle.Core.Lifetime {

    /// <summary>
    /// Track an instance until disposed.
    /// </summary>
    public class DisposableAttribute : TrackingPolicyAttribute
    {
        /// <summary>
        /// Returns a reference implementing the Disposable tracking policy
        /// </summary>
        public override IReference Apply(object instance) {
            return new DisposeTrackingReference(instance);
        }

        private class DisposeTrackingReference : IReference {

            INotifyDisposed instance;

            public DisposeTrackingReference(object instance) {
                INotifyDisposed obj = instance as INotifyDisposed;
                if (obj == null) {
                    throw new ArgumentException("instance must implement " + typeof(INotifyDisposed).FullName, "instance");
                }
                this.instance = obj;
                obj.Disposed += OnDispose;
            }

            private void OnDispose(object sender, EventArgs e) {
                INotifyDisposed dn = sender as INotifyDisposed;
                if (dn != null) {
                    dn.Disposed -= OnDispose;
                }
                Interlocked.CompareExchange(ref instance, null, dn);
            }

            #region IReference Members

            public object Target {
                get { return Interlocked.CompareExchange(ref instance, null, null); }
            }

            public bool IsValid {
                get { return Interlocked.CompareExchange(ref instance, null, null) != null; }
            }

            #endregion
        }
    }
}
